<?php
/**
 * User: 苏翔
 * Date: 2024/8/16 14:07
 */

namespace App\Dao;

use App\HscoinConf;
use App\Model\HscoinBalanceModel;
use App\Model\HscoinBillModel;
use App\Model\HscoinStatsModel;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;

class HscoinBillDao extends BaseDao
{

    #[Inject]
    protected HscoinBillModel $model;
    #[Inject]
    protected HscoinBalanceModel $balanceModel;

    #[Inject]
    protected HscoinStatsModel $statsModel;

    /**
     * 添加记录
     *
     * @param int $category 类别
     * @param float $amount 数量
     * @param int $link_id 关联ID
     * @param int $uid 用户ID
     * @param string $mark 备注
     * @return int|false 记录ID或false
     * @todo check 重复,first 可以从消息记录日志里面
     * @todo uid,link_id 作为主键
     */
    function add(int $category, int $link_id, float $link_amount, float $amount, int $uid = 0, string $mark = ''): int
    {
        $rt = 0;

        if (!$this->checkDuplicated($category, $link_id, HscoinConf::STATUS_ENABLED)) {
            return [false, '重复'];
        }

        $isAddBalance = isset(HscoinConf::$categoryIncomeLabelMap[$category]);
        $data = compact('category', 'link_amount', 'amount', 'link_id', 'uid', 'mark');
        $this->model->getConnection()->transaction(function () use (&$rt, $uid, $data, $isAddBalance, $amount, $category) {
            $balanceRawCount = $isAddBalance ? 'cnt+' . $amount : 'cnt-' . $amount;
            $whereTotal = ['cache_type' => HscoinConf::STATS_TYPE_BALANCE];

            $whereCategory = [
                'category' => $category,
                'cache_type' => $category > 0
                    ? HscoinConf::STATS_TYPE_CATEGORY_INCOME
                    : HscoinConf::STATS_TYPE_CATEGORY_EXPENSE
            ];
            $rs1 = $this->statsModel->where($whereTotal)->update(['cnt' => Db::raw($balanceRawCount)]);
            $rs1 = $this->statsModel->where($whereCategory)->update(['cnt' => Db::raw($balanceRawCount)]);


            $whereCurrent = ['uid' => $uid];
            $userBalanceData = ['cnt' => Db::raw($balanceRawCount),];
            if ($category > 0) {
                $userBalanceData['income_cnt'] = Db::raw("income_cnt+$amount");
                $userBalanceData['today_income_cnt'] = Db::raw("today_income_cnt +$amount");
            }
            $this->balanceModel->where($whereCurrent)->update($userBalanceData);

            $balanceTotal = $this->statsModel->where($whereTotal)->value('cnt');
            $balanceCurrent = $this->balanceModel->where($whereCurrent)->value('cnt');


            $data['balance'] = $balanceTotal;
            $data['user_balance'] = $balanceCurrent;
            $data['status'] = HscoinConf::STATUS_ENABLED;
            $data['created_at'] = date('Y-m-d H:i:s');
            $id = $this->model->insertGetId($data);
            $rt = $id;
        });
        return $rt;

    }

    function checkDuplicated($category, $link_id, $status, $limit = true)
    {
        $startId = $this->getStartIdForChecked();
        $where = compact('category', 'link_id');
        if ($limit) {
            $where[] = ['id', '>', $startId];
        }

        $first = $this->model->where($where)->first(['status']);
        $rt = true;
        if ($first && ($status === $first['status'])) {
            $rt = false;
        }
        return $rt;
    }

    function getStartIdForChecked(): int
    {
        $maxId = (int)$this->model->orderBy('id', 'desc')->value('id');
        return $maxId - HscoinConf::CHECK_HANDLED_BILL_NUM;
    }

    /**
     * 取消
     * @param $category
     * @param $link_id
     * @return array
     * @throws \Throwable
     * @todo 事务优化,1只留两个update,2,先读余额先插入日志
     * @todo 补充待修正和测试
     * @author 苏翔
     * @date 2024-08-16 17:42
     */
    function cancel($category, $link_id): int
    {
        $rt = 0;
        $first = $this->model->where(compact('category', 'link_id'))->orderBy('id', 'desc')->first();
        if (!$first) {
            return 0;// [$rt, "不存在"];
        }

        if (HscoinConf::STATUS_ENABLED != $first['status']) {
            return 0;//[$rt, "已经操作"];
        }
        $uid = $first['uid'];

        $isAddBalance = !isset(HscoinConf::$categoryIncomeLabelMap[$category]);


        $this->model->getConnection()->transaction(function () use (&$rt, $first, $uid, $isAddBalance) {
            $amount = $first['amount'];
            $balanceRawCount = $isAddBalance ? 'cnt+' . $amount : 'cnt-' . $amount;
            $whereTotal = ['cache_type' => HscoinConf::STATS_TYPE_BALANCE];
            $category = $first['category'];
            $whereCategory = [
                'category' => $category,
                'cache_type' => $category > 0
                    ? HscoinConf::STATS_TYPE_CATEGORY_INCOME
                    : HscoinConf::STATS_TYPE_CATEGORY_EXPENSE
            ];
            $rs1 = $this->statsModel->where($whereTotal)->update(['cnt' => Db::raw($balanceRawCount)]);
            $rs1 = $this->statsModel->where($whereCategory)->update(['cnt' => Db::raw($balanceRawCount)]);

            $whereCurrent = ['uid' => $uid];
            $userBalanceData = ['cnt' => Db::raw($balanceRawCount),];
            if ($category > 0) {
                $userBalanceData['income_cnt'] = Db::raw("income_cnt-$amount");
                $userBalanceData['today_income_cnt'] = Db::raw("today_income_cnt -$amount");
            }
            $this->balanceModel->where($whereCurrent)->update($userBalanceData);
            $balanceTotal = $this->statsModel->where($whereTotal)->value('cnt');
            $balanceCurrent = $this->balanceModel->where($whereCurrent)->value('cnt');


            $data['balance'] = $balanceTotal;
            $data['user_balance'] = $balanceCurrent;
            $data['category'] = $first['category'];
            $data['link_id'] = $first['link_id'];
            $data['link_amount'] = $first['link_amount'];
            $data['amount'] = $first['amount'];
            $data['uid'] = $first['uid'];
            $data['status'] = HscoinConf::STATUS_DISABLED;
            $data['pid'] = $first['id'];
            $data['mark'] = '取消后系统对冲';
            $data['created_at'] = date('Y-m-d H:i:s');
            $id = $this->model->insertGetId($data);
            $rt = $id;
        });
        return $rt;

    }


    function getList($uid = 0, $category = 0, $min_id = 0, $max_id = 0, $size = 10): array
    {
        $size = max(1, (int)$size);
        $where = compact('uid', 'category');
        $where = array_filter($where);
        $orderDirection = 'desc';
        if ($min_id) {
            $where[] = ['id', '>', $min_id];
            $orderDirection = 'asc';
        } elseif ($max_id) {
            $where[] = ['id', '<', $max_id];
        }
        return $this->model->where($where)->orderBy('id', $orderDirection)->limit($size)->get()->toArray();
    }
}
